#ifndef GAMEHANDLER_H
#define GAMEHANDLER_H
#include "main.h"
#include "routemap.h"

#define guiFile "handler.glade"
#define guiTopLevel "handler"

using namespace Glib;
using namespace Gtk;
using namespace std;
using namespace Gtk::Stock;
enum BotState{
    none,
	awaiting_connect,
    connected,
    initialized,
    running,
    paused,
    connection_error,
};

template<class B>
class GameHandler;
class Bot;


class BotEvent{
	protected:
	string name;
	sigc::signal<void> run;
	Bot* bot;

	void execute(){
		run.emit();
	}
	BotEvent(string name, Bot* bot):bot(bot){
		run.connect(sigc::mem_fun(this, &BotEvent::doAction));
	}

protected:
	virtual void action(){}//for extending

	void doAction(){
		action();
	}
};

/**
 * user command to the bot.
 * mostly for testing purposes
 * */

class BotCommand: public BotEvent{
	Button button;
	BotCommand(string name, Bot* bot): BotEvent(name, bot){
		button.set_label(name);

	}
};



class Bot{
	vector<BotEvent> events;

    public:

    Widget* infos;
    BotState state;
    Bot():infos(){
        state = none;
        infos = NULL;
    };
    virtual bool connect()=0;
    virtual bool run(){
		if(state==connected)
			state = running;
		else if(connect()){
			state = running;
			return true;
		}
		else
			return false;
		return true;
    }
    virtual bool round()=0;

};



/**
 * \brief gamehandler
 * a basis for all your bots (on one team) you are quite free to fill this in. For small games that are
 * specifically created for EZ you could even inplement the game here.
 * it is a template for your bot type, so to extend it you should use CustomHandler:public/private GameHandler<CustomBot>
 */

template<class B>
class GameHandler
{
    protected:
        vector<Bot*> allbots;
    public:
        Window* win;
        /** Default constructor */

    GameHandler(){
		runner = 0;
		cout << "starting GuiBuild" << endl;

        try{
            guiBuilder = Builder::create_from_file(guiFile);
            win = new Window;
            guiBuilder->get_widget(guiTopLevel, (Widget*&) win);
        }catch(Gtk::BuilderError e){
            cerr<< e.what() <<endl;

        }catch(...){
            cerr << "something else went wrong\n";
        }

		cout << "got topLevel" << endl;
		//macro to load an item from the builder in the the equally named member variable
		#define GETFROMBUILDER(name) guiBuilder->get_widget(ustring( #name ), ((Widget*&) name));

		GETFROMBUILDER(toolbar);
		GETFROMBUILDER(botsInspector1);
		GETFROMBUILDER(botsInspector2);
		GETFROMBUILDER(menubar);
		#undef GETFROMBUILDER
		handlerActions = RefPtr<Gtk::ActionGroup>::cast_dynamic(guiBuilder->get_object("handlerActions"));
		handlerAccels = RefPtr<Gtk::AccelGroup>::cast_dynamic(guiBuilder->get_object("handlerAccels"));
		win->add_accel_group(handlerAccels);

		#define GETACTION(name, func) name = handlerActions->get_action(#name);\
			name->signal_activate().connect(sigc::mem_fun(*this, &GameHandler::func));

		GETACTION(addBotAction, onAddBot)
		GETACTION(addControllerBotAction, onAddControllerBot)
		GETACTION(connectAllAction, onConnect)
		GETACTION(runAllAction, onRunAll)

		#undef	GETACTION
//		uiman = Gtk::UIManager::create();
	//	uiman->insert_action_group(handlerActions);

		win->show_all();
	}



	static bool sRound(Bot* obj){
		if(obj->state == running)
			return obj->round();
		if(obj->state == awaiting_connect){
			cout << "reconnecting \n";
			Glib::usleep(500000);
			if(obj->connect())
					obj->state=running;
		}
		return false;
	}
	/** thread for running all bots. Bots are run sequentially in order of creation
	 *
	 * */
	virtual void runnerThread(){
        while (true){
			for_each(allbots.begin(), allbots.end(), GameHandler::sRound);
            Glib::Thread::yield	();
            Glib::usleep(100);
			cout << ".";
        }
    }

        /** Default destructor */
        virtual ~GameHandler(){};


private:
    void onAddBot(){
        addBot();
		menubar->accelerate(*win);
    }
    void onAddControllerBot(){
        addControllerBot();
    }
    void onRunAll(){
        runAll();
    }
    void onConnect(){
        connect();
    }
public:

        virtual bool connect(){
            vector<Bot*>::iterator it;
            for(it = allbots.begin(); it<allbots.end(); it++){
                ((Bot*) *it)->connect();
            }
            return true;
        }

        virtual void addBot(){
            addBot(
				*createBot()
			);
        }
		virtual void addControllerBot(){};

        virtual void addBot(B& bot){
            if( bot.infos ){
				int page = botsInspector1->append_page(*bot.infos, bot.name);
				botsInspector1->set_tab_detachable(*bot.infos);
				botsInspector1->set_tab_reorderable(*bot.infos);
                bot.infos->show_all();
                botsInspector1->set_current_page( page);
                botsInspector1->show();
            }
            allbots.push_back(&bot);
        };
        virtual void runAll(){
            vector<Bot*>::iterator it;
            for(it = allbots.begin(); it<allbots.end(); it++){
                ((Bot*) *it)->run();
            }
			Glib::Thread::create(sigc::mem_fun(*this, &GameHandler::runnerThread), true);
        };
        virtual void resetAll()=0;

        virtual B* createBot()=0;
		virtual bool threadRunning(){
			return runner!=0;
		}
protected:
	Glib::Thread* runner;


public://gui stuff
	Glib::RefPtr<Gtk::Builder> guiBuilder;
		RefPtr<Gtk::ActionGroup> handlerActions;
		RefPtr<Gtk::AccelGroup>  handlerAccels;
		RefPtr<Gtk::UIManager>  uiman;
		Window* handlerGui;
		Toolbar* toolbar;
		MenuBar* menubar;
		Notebook* botsInspector1;
		Notebook* botsInspector2;
		RefPtr<Gtk::Action> runAllAction;
		RefPtr<Gtk::Action> addBotAction ;
		RefPtr<Gtk::Action> addControllerBotAction;
		RefPtr<Gtk::Action> connectAllAction;
};

#endif // GAMEHANDLER_H
